﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using CSScriptLib;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Qing.Dll;
using Qing.Lang;

namespace Qing.Std {

    class Anti : Native {
        public override string Name { get; set; } = "取反";
        public override string Desc { get; set; } = "参数1-任意，返回逻辑；对参数1转为逻辑值后再取反";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                return new Expr(TP.Bool, !args[0].ToBool());
            }

            return Expr.Err("取反函数参数不足");
        }

    }

    class Del : Native {
        public override string Name { get; set; } = "删除";
        public override string Desc { get; set; } = "参数1-字符串|对象，参数2-逻辑|字符串，返回任意；参数1为字符串时，从语境中删除对应的值，若此时参数2为真，限定从当前语境删除；当参数1为对象时，参数2必须为字符串，从对象中删除参数2对应的属性或方法";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                if (args.Count == 1) {
                    return ctx.Remove(args[0].Str());
                } else {
                    if (args[1].Tp == TP.Bool && (bool)args[1].Val! == true) {
                        return ctx.RemoveNow(args[0].Str());
                    }else if (args[0].Tp == TP.Obj && args[1].Tp == TP.Str) {
                        return args[0].Obj().RemoveNow(args[1].Str());
                    }
                }
                
            }

            return Expr.Err("删除函数参数错误");
        }

    }

    class Copy : Native {
        public override string Name { get; set; } = "复制";
        public override string Desc { get; set; } = "参数1-任意，返回任意；复制参数1，注意是简单复制，对于集合类型，只是简单复制引用";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                Expr res = args[0].Dup();
                if (args[0].List != null) {
                    List<Expr> list = new List<Expr>();
                    foreach(var item in args[0].List!) {
                        list.Add(item.Dup());
                    };
                    res.List = list;
                }
                return res;
            }
            return Expr.Err("复制函数参数不足");
        }

    }

    class Clone : Native {
        public override string Name { get; set; } = "拷贝";
        public override string Desc { get; set; } = "参数1任意，返回任意；复制参数1，这里时深拷贝，对于集合类型，也会将内部的数据也会复制一份新的";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                return args[0].Clone();
            }
            return Expr.Err("拷贝函数参数不足");
        }

    }

    class Eval : Native {
        public override string Name { get; set; } = "执行";
        public override string Desc { get; set; } = "参数1-字符串|大括号，返回任意；执行字符串或大括号中的代码";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if(args.Count > 0) { 
                if (args[0].Tp == TP.Brace) {
                    return Expr.EvalExprs(args[0].List!, ctx);
                }else if (args[0].Tp == TP.Str) {
                    return Expr.EvalExprs(new Parser().Parse(args[0].Str(), ctx), ctx);
                }
                
            }
            return Expr.Err("执行函数参数不足");
        }

    }

    class TypeOf : Native {
        public override string Name { get; set; } = "取类型";
        public override string Desc { get; set; } = "参数1-任意，返回字符串；返回参数1对应类型的字符串";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                return new Expr(TP.Str, TPkit.typeName(args[0].Tp));
            }
            return Expr.Err("取类型函数参数不足");
        }

    }

    class RawType : Native {
        public override string Name { get; set; } = "内部类型";
        public override string Desc { get; set; } = "参数1-对象，返回字符串；返回对象内部原生对象的类型";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {
            if(args.Count < 1) {
                return Expr.Err("@内部类型函数的参数不足");
            }
            if (args[0].Tp != TP.Obj) {
                return Expr.Err("@内部类型函数只接受对象类型的参数");
            }
            return new Expr(TP.Str, args[0].Obj().Raw.GetType().ToString());
        }

    }


    class Include : Native {
        public override string Name { get; set; } = "包含";
        public override string Desc { get; set; } = "参数-1字符串，可选参数2-逻辑，返回任意|对象；执行参数1对应文件中的代码，如果参数2为真，则会在一个对象语境中执行代码，并返回这个对象";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                if (args[0].Tp == TP.Obj) {
                    var map = args[0].Ctx().Map;
                    foreach(var item in map) {
                        ctx.PutNow(item.Key, item.Value);
                    }
                    return new Expr(TP.Int, map.Count);
                }else if (args[0].Tp == TP.Str) {
                    string path = args[0].Str();
                    string script = path;

                    bool module = false;
                    if (args.Count > 1) {
                        module = args[1].ToBool();
                    }

                    if (path.StartsWith("http://") || path.StartsWith("https://")) {
                        HttpWebRequest request = WebRequest.CreateHttp(path);
                        request.Method = "GET";

                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                        using (Stream responseStream = response.GetResponseStream()) {
                            using (StreamReader sReader = new StreamReader(responseStream)) {
                                script = sReader.ReadToEnd();
                            }
                        }

                        if (module) {
                            Obj moduleCtx = new Obj(Env.LibCtx);
                            Expr.EvalExprs(new Parser().Parse(script, moduleCtx, path), moduleCtx);
                            return new Expr(TP.Obj, moduleCtx);

                        } else {
                            return Expr.EvalExprs(new Parser().Parse(script, ctx), ctx);
                        }


                    } else {
                        if (!path.StartsWith("/") && !path.Contains(":")) {
                            path = Directory.GetCurrentDirectory() + '/' + path;
                        }
                        if (!File.Exists(path)) {
                            return Expr.Err("包含函数的文件参数对应的文件不存在");
                        }

                        script = File.ReadAllText(path);


                        string originDir = Directory.GetCurrentDirectory();

                        FileInfo fi = new FileInfo(path);
                        string dir = fi.DirectoryName!;
                        Directory.SetCurrentDirectory(dir);


                        if (module) {
                            Obj moduleCtx = new Obj(Env.LibCtx);
                            Expr.EvalExprs(new Parser().Parse(script, moduleCtx, path), moduleCtx);
                            Directory.SetCurrentDirectory(originDir);
                            return new Expr(TP.Obj, moduleCtx);

                        } else {
                            Expr res = Expr.EvalExprs(new Parser().Parse(script, ctx), ctx);
                            Directory.SetCurrentDirectory(originDir);
                            return res;
                        }


                    }

                    
                    
 
                }

            }
            return Expr.Err("包含函数参数不足");
        }
    }



    class Import : Native {
        public override string Name { get; set; } = "引入";
        public override string Desc { get; set; } = "参数1-字符串，返回模块；将参数1对应的代码文件作为模块引入到当前代码中，模块在第一次取值时会转换为对象，模块是全局唯一的";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                if (args[0].Tp == TP.Str) {
                    string path = args[0].Str();
                    string fullPath = path;
                    string script = "";
                    if (path.StartsWith("http://") || path.StartsWith("https://")) {
                        HttpWebRequest request = WebRequest.CreateHttp(path);
                        request.Method = "GET";

                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                        using (Stream responseStream = response.GetResponseStream()) {
                            using (StreamReader sReader = new StreamReader(responseStream)) {
                                script = sReader.ReadToEnd();
                            }
                        }

                    } else {
                        if (!path.StartsWith("/") && !path.Contains(":")) {
                            path = Directory.GetCurrentDirectory() + '/' + path;
                        }
                        if (!File.Exists(path)) {
                            return Expr.Err("引入函数的文件参数对应的文件不存在");
                        }

                        fullPath = Path.GetFullPath(path);
                        script = File.ReadAllText(path);
                    }

                    
                    if (Env.ModuleMap.ContainsKey(fullPath)) {
                        return Env.ModuleMap[fullPath];
                    } else {
                         
                        /*Ctx moduleCtx = new Ctx(Env.libCtx);
                        Expr.evalExprs(Parser.makeExprs(script, moduleCtx), moduleCtx);
                        Expr module = new Expr(TP.obj, moduleCtx);
                        Env.moduleMap[fullPath] = module;
                        return module;*/
                        Expr module = new Expr(TP.Module, 0, new List<Expr>());
                        module.List!.Add(new Expr(TP.Str, fullPath));
                        module.List!.Add(new Expr(TP.Str, script));
                        Env.ModuleMap[fullPath] = module;
                        return module;
                    }
                 
                }
                return Expr.Err("引入函数参数错误");
            }
            return Expr.Err("引入函数参数不足");
        }
    }


    class LoadDll : Native {
        public override string Name { get; set; } = "加载动态库";
        public override string Desc { get; set; } = "参数1-字符串，可选参数2-字符串，返回对象；加载参数1对应的动态库文件，参数2是动态库中用于对接青语言的类名，默认类名QingLib.LibObj，返回生成的对象";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if(args.Count > 0 && args[0].Tp == TP.Str) {

                string libPath = "QingLib.LibObj";
                if(args.Count > 1 && args[1].Tp == TP.Str) {
                    libPath = args[1].Str();
                }

                try {
                    string path = args[0].Str();
                    if (!path.StartsWith("/") && !path.Contains(":")) {
                        path = Directory.GetCurrentDirectory() + '/' + path;
                    }

                    Assembly assembly = Assembly.LoadFile(path);
                    Type type = assembly.GetType(libPath)!;
                    object instance = assembly.CreateInstance(libPath)!;

                    Obj dllObj = (Obj)instance;

                    return new Expr(TP.Obj, dllObj);
                } catch(Exception e) {
                    return Expr.Err(e.Message);
                }
            }
            return Expr.Err("加载动态库函数参数错误");
        }
    }


    public class CSharpScriptBridge {
        public Expr Params { get; set; } = new Expr(TP.None, 0);
        public Expr Result { get; set; } = new Expr(TP.None, 0);

        public CSharpScriptBridge() { }
        public CSharpScriptBridge(Expr args, Expr result) {
            this.Params=args;
            this.Result=result;
        }
    }

    class RunCSharpScript : Native {
        public override string Name { get; set; } = "运行原生脚本";
        public override string Desc { get; set; } = "参数1-任意，参数2-任意，参数3-字符串，命名参数-#文件模式-逻辑，命名参数-#引用列表-字符串数组，命名参数-#库列表-字符串数组，返回任意；以脚本的形式运行一段嵌入的C#代码，参数1为入参，参数2为返回值，参数3为要运行的C#代码或文件路径，命名参数#文件模式 默认为假，若为真则参数3为指定的脚本文件，可指定要应用的命名空间和程序集";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if(args.Count < 3) {
                return Expr.Err("运行原生脚本函数参数不足");
            }
            if (args[2].Tp != TP.Str) {
                return Expr.Err("运行原生脚本函数参数类型错误");
            }

            CSharpScriptBridge bridge = new CSharpScriptBridge();
            if (args[0].Tp == TP.None) {
                args[0] = new Expr(TP.None, 0);
            }
            bridge.Params = args[0];

            if (args[1].Tp == TP.None) {
                args[1] = new Expr(TP.None, 0);
            }
            bridge.Result = args[1];

            List<string> imports = new List<string> { };
            List<string> dlls = new List<string> { };

            string script = args[2].Str();
            bool isFile = false;
            if(namedArgs != null) {
                foreach(Expr item in  namedArgs) {
                    if (item.List![0].Str() == "#文件模式") {
                        isFile = item.List![1].ToBool();
                    }

                    if (item.List![0].Str() == "#引用列表" && item.List![1].Tp == TP.Arr) {
                        foreach(Expr itor in item.List![1].List!) {
                            if(itor.Tp == TP.Str) {
                                imports.Add(itor.Str());
                            }
                        }
                    }

                    if (item.List![0].Str() == "#库列表" && item.List![1].Tp == TP.Arr) {
                        foreach (Expr itor in item.List![1].List!) {
                            if (itor.Tp == TP.Str) {
                                dlls.Add(itor.Str());
                            }
                        }
                    }
                }
            }

            if (isFile) {
                if(!script.StartsWith("/") && !script.Contains(':')) {
                    script = Directory.GetCurrentDirectory() + '/' + script;
                }
                if (!File.Exists(script)) {
                    return Expr.Err("运行原生脚本函数接收的脚本文件不存在");
                }
                script = File.ReadAllText(script);
            }



            string scriptHead = "using System;\nusing Qing;\nusing Qing.Lang;\n";
            foreach(var item in imports) {
                scriptHead += "using " + item + ";\n";
            }

            script = scriptHead + @"using System;
                           public class Script
                           {
        public void Func(dynamic _Params, dynamic _Result){ 
            " + script + "\n}\n}\n return new Script();\n";



            try {


                //Console.WriteLine(script);

                CSScript.Evaluator.ReferenceAssemblyOf(args[1]);
                CSScript.Evaluator.ReferenceAssemblyOf(script);
                CSScript.Evaluator.ReferenceAssemblyByName(dlls.ToArray());

                CSScript.Evaluator.ReferenceDomainAssemblies();

                var code = CSScript.Evaluator.Eval(script);
                code.Func(args[0], args[1]);
                
                return args[1];
            } catch (Exception ex) {
                return Expr.Err("运行原生脚本函数发生异常，原因：" + ex.Message);
            }
        }
    }


}
